// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Copyright (c) 2006 by Lattice Semiconductor Corporation
// --------------------------------------------------------------------
//
// Permission:
//
//   Lattice Semiconductor grants permission to use this code for use
//   in synthesis for any Lattice programmable logic product.  Other
//   use of this code, including the selling or duplication of any
//   portion is strictly prohibited.
//
// Disclaimer:
//
//   This VHDL or Verilog source code is intended as a design reference
//   which illustrates how these types of functions can be implemented.
//   It is the user's responsibility to verify their design for
//   consistency and functionality through the use of formal
//   verification methods.  Lattice Semiconductor provides no warranty
//   regarding the use or functionality of this code.
//
// --------------------------------------------------------------------
//           
//                     Lattice Semiconductor Corporation
//                     5555 NE Moore Court
//                     Hillsboro, OR 97214
//                     U.S.A
//
//                     TEL: 1-800-Lattice (USA and Canada)
//                          503-268-8001 (other locations)
//
//                     web: http://www.latticesemi.com/
//                     email: techsupport@latticesemi.com
//
// --------------------------------------------------------------------
//
//  Project:           7:1 LVDS Video Interface
//  File:              LVDS_7_to_1_RX_sapphire.v
//  Title:             LVDS_7_to_1_RX_sapphire
//  Description:       Rx module of this reference design for Sapphire architecture
//
// --------------------------------------------------------------------
// Code Revision History :
// --------------------------------------------------------------------
// Ver: | Author   | Mod. Date  | Changes Made:
// V1.0 | shossner | 2010-04-25 | Initial Release
// V1.1 | shossner | 2010-11-03 | Accomodation for IPexpress module update
//
// --------------------------------------------------------------------

`timescale 1 ns/ 1 ps

module LVDS_7_to_1_RX 
     (
      dphase_sel , 
      dphase_in  ,       
      RCLK_in    ,
      R0_in      ,
      R1_in      ,
      R2_in      ,
      R3_in      ,
                 
      RCLK_out   ,
      R0_out     ,
      R1_out     ,
      R2_out     ,
      R3_out     ,

      eclk,
      stop,
      sclk,
      dphase_lock,
      dphase_out ,
      rxpll_lock 
   );

   input       dphase_sel;  // 0: auto phase, 1: manual phase from DIP switches 
   input [3:0] dphase_in;   // from DIP switches
   input       RCLK_in;  // LVDS clock input pair
   input       R0_in;    // LVDS data input pair 0
   input       R1_in;    // LVDS data input pair 1
   input       R2_in;    // LVDS data input pair 2
   input       R3_in;    // LVDS data input pair 3
   
   output [6:0] RCLK_out;  // 7-bit parallel clock data
   output [6:0] R0_out;    // 7-bit parallel data
   output [6:0] R1_out;    // 7-bit parallel data
   output [6:0] R2_out;    // 7-bit parallel data
   output [6:0] R3_out;    // 7-bit parallel data
         
   output       eclk;      // PLL output, to slave Tx if necessary
   output       stop;      // eclksynca control signal out (to transmitter, if necessary)
   output       sclk;      // System clock, Rcv outputs clocked on rising edge
   output       dphase_lock;  // status output, from bit_align module
   output [3:0] dphase_out;   // selected phase, from bit_align module
        
   output       rxpll_lock;  // Rx PLL lock outp
   
`ifdef _VCP  // used to detect Aldec Verilog simulation and reduce simulation time
   parameter   COUNT_LEN = 11;  // to reduce the simulation time
`else
   parameter   COUNT_LEN = 19;
`endif



   wire        pll_lock;            // PLL locked status
            
   wire  [3:0] rx_di;               // 4 serial input data streams
   wire  [6:0] rxdata_out [3:0];    // array of 4 7-bit recovered data words
         
   wire  [6:0] RCLK_out_sclk;       // 7-bit parallel clock data, sclk domain
   wire  [6:0] RCLK_out_rclk;       // 7-bit parallel clock data, RCLK_in domain
         
   reg         reset_sync;          // reset to all modules
         
   wire        lost_sync;           // detected PLL loss-of-lock
   reg  [COUNT_LEN-1:0] delay_count = 0;  // delay after RCLK_in established
   reg         release_reset = 0;   // asserts at end of delay
  
   
   reg         pll_lock_1;          // sync pipe
   reg         pll_lock_sync;       // sync pipe

   wire [3:0]  dphase; 	            // output state from bit_align module
   reg         dphase_lock_d1;      // sync pipe
   reg         dphase_lock_d2;      // sync pipe

   wire        slip;
   wire        pll_phase_dir;
   wire        pll_phase_step;

//-------------------------------------//
//-- assign (non-process) operations --//
//-------------------------------------//
   assign dphase_out = !dphase_sel ? dphase : dphase_in;   // 0: auto phase, 1: manual phase from DIP switches 
      

//--------------------------------------------------------------------
//-- IPexpress GDDR_7:1 Rx module
//--------------------------------------------------------------------
 
ip_gddr71rx LVDS_71_Rx (
    .alignwd      (slip), 
    .clk_phase    (RCLK_out_sclk), 
    .clkin        (RCLK_in), 
    .lock         (pll_lock), 
    .phasedir     (pll_phase_dir), 
    .phaseloadreg (1'b0), 
    .phasestep    (pll_phase_step), 
    .ready        (), 
    .eclk         (eclk),
    .sclk         (sclk), 
   // .start        (1'b1), 
    .sync_clk     (RCLK_in), 
    .sync_reset   (reset_sync), 
    .datain       (rx_di), 
    .q0           (rxdata_out[0]), 
    .q1           (rxdata_out[1]), 
    .q2           (rxdata_out[2]), 
    .q3           (rxdata_out[3])
); 

   assign rxpll_lock = pll_lock_sync;
   assign RCLK_out = RCLK_out_sclk;
   assign rx_di = {R3_in, R2_in, R1_in, R0_in};

   assign R0_out = rxdata_out[0];
   assign R1_out = rxdata_out[1];
   assign R2_out = rxdata_out[2];
   assign R3_out = rxdata_out[3];
   assign stop   = !pll_lock_sync;  // ensure transmitter sclk circuits have same phase 

   //--------------------------------------------------------------------
   //-- Pass RCLK_out from sclk to RCLK_in domain
   //--------------------------------------------------------------------
   bus_sync #    (.DATA_BITS (7))
            bus_sync_inst
                 (
                  .clki      (sclk), 
                  .datai     (RCLK_out_sclk),  // 7-bit clock word from Rcv module
                  .clko      (RCLK_in),  
                  .datao     (RCLK_out_rclk)   // clock word to word_align module
                );      

   //--------------------------------------------------------------------
   //-- Automatic bit alignment control
   //--------------------------------------------------------------------
   bit_align_ctl bit_aln_ctl_inst
                 (
                  .rx_clk      (RCLK_in), 
                  .reset       (reset_sync),  
                  .bit_aln_en  (pll_lock_sync),  // slave to PLL
                  .rxclk_word  (RCLK_out_rclk),
                  .phase_dir   (pll_phase_dir),
                  .phase_rot   (pll_phase_step),
                  .dphase      (dphase),
                  .dphase_lock (dphase_lock)
                 );      

   //--------------------------------------------------------------------
   //-- Word Alignment control 
   //--------------------------------------------------------------------
   
   word_align_ctl wd_aln_ctl_inst
                  (
                   .clk             (sclk), 
                   .rst             (reset_sync),  
                   .clock_word      (RCLK_out_sclk), 
                   .align_enable    (dphase_lock_d2), // slave to bit_align_ctl and PLL
                   .slip            (slip) 
                  );
        

   // Using double Flip-Flops before passing asynchronous signal to the
   // sclk clock domain
   always @(posedge sclk or posedge reset_sync)
   begin
      if(reset_sync == 1'b1) begin
         dphase_lock_d1 <= 0;
         dphase_lock_d2 <= 0;
      end else begin
         dphase_lock_d1 <= dphase_lock && pll_lock_sync;
         dphase_lock_d2 <= dphase_lock_d1;
      end
   end


// synchronize PLL_lock into RCLK_in domain
// aysync reset because RCLK_in is not dependable
   always @(posedge RCLK_in or negedge pll_lock)
   begin
      if (pll_lock == 1'b0) begin
         pll_lock_1    <= 1'b0;
         pll_lock_sync <= 1'b0;
      end else begin
         pll_lock_1    <= 1'b1;
         #4 pll_lock_sync <= pll_lock_1;
      end
   end


//--------------------------------------------------------------------
   //-- Automatic synchronizing Logic :
   //--    The following logic will automatically synchronize the LVDS
   //--    receiving data pairs to the 7-bit data boundary.  When the
   //--    LVDS conection is lost(lost_sync = 1), it will be reset and
   //--    re-sync again when a stable LVDS clock is connected back on.
   //--------------------------------------------------------------------

   // Detecting if the PLL is out of the "LOCK" state,
   // Only sensative to pll_lock when delay_count has saturated
   // Disconnecting LVDS loopback cable will cause this to happen
//   assign lost_sync = delay_count[COUNT_LEN-1] & ~pll_lock;
   assign lost_sync = 0;


// Delay counter used for the automatic synchronizing Logic
//  async reset used as RCLK_in is not dependable      
   always @(posedge RCLK_in or posedge lost_sync)
   begin
      if (lost_sync == 1'b1) 
         delay_count <= 0;
      else
         if (delay_count[COUNT_LEN-1] == 1'b0) 
            delay_count <= delay_count + 1;
   end

   
//  release reset to downstream logic after RCLK_in stable for many clocks.
//  async reset used as RCLK_in is not dependable      
always @(posedge RCLK_in or posedge lost_sync)
   begin
      if (lost_sync == 1'b1) 
         release_reset <= 1'b0;
      else
         if (release_reset == 1'b0) 
            release_reset <= delay_count[COUNT_LEN-2];//min. 9.48 us (i.e.,RCLK_in = 108 MHz), with smallest delay_count[10]
   end 

   // 'reset_sync' is synchronous in RCLK_in domain
   //  async reset used as RCLK_in is not dependable      
   always @(posedge RCLK_in or posedge lost_sync)
   begin
      if (lost_sync == 1'b1) begin
         reset_sync <= 1'b1;
      end else begin
         reset_sync <= !release_reset;
      end
   end




endmodule


